package com.code.google.mdsc.io.xml.impl.factory;

import com.code.google.mdsc.model.Debtor;
import com.code.google.mdsc.sepa.AccountIdentificationSEPA;
import com.code.google.mdsc.sepa.ActiveOrHistoricCurrencyAndAmountSEPA;
import com.code.google.mdsc.sepa.ActiveOrHistoricCurrencyCodeEUR;
import com.code.google.mdsc.sepa.BranchAndFinancialInstitutionIdentificationSEPA3;
import com.code.google.mdsc.sepa.CashAccountSEPA2;
import com.code.google.mdsc.sepa.DirectDebitTransactionInformationSDD;
import com.code.google.mdsc.sepa.DirectDebitTransactionSDD;
import com.code.google.mdsc.sepa.FinancialInstitutionIdentificationSEPA3;
import com.code.google.mdsc.sepa.MandateRelatedInformationSDD;
import com.code.google.mdsc.sepa.PartyIdentificationSEPA1;
import com.code.google.mdsc.sepa.PartyIdentificationSEPA2;
import com.code.google.mdsc.sepa.PaymentIdentificationSEPA;
import com.code.google.mdsc.sepa.PurposeSEPA;
import com.code.google.mdsc.sepa.RemittanceInformationSEPA1Choice;

/**
 * Generates the DirectDebitTransactionInformation XML part.
 * 
 */
public class DrctDbtTxInfFactory extends PartialSEPAFactory {

	/**
	 * Starts the generation of the DirectDebitTransactionInformation XML part.
	 * 
	 * @param currentDebtor
	 *            the debtor of this direct debit transaction.
	 * 
	 * @return the {@link DirectDebitTransactionInformationSDD} with the
	 *         specified data.
	 */
	public DirectDebitTransactionInformationSDD generate(Debtor currentDebtor) {
		DirectDebitTransactionInformationSDD generated = OBJECT_FACTORY
				.createDirectDebitTransactionInformationSDD();

		generated.setPmtId(createPaymentIdentification(currentDebtor));

		generated.setInstdAmt(createInstructionAmount(currentDebtor));

		// generated.setChrgBr(ChargeBearerTypeSEPACode.SLEV); recommended not
		// to set here, instead on Payment Information level

		generated.setDrctDbtTx(createDrctDbtTx(currentDebtor));

		// generated.setUltmtCdtr(createUltimateCreditor());

		generated.setDbtrAgt(createDebtorAgent(currentDebtor));

		generated.setDbtr(createDebtor(currentDebtor));

		generated.setDbtrAcct(createDebtorAccount(currentDebtor));

		// ddtisdd.setUltmtDbtr(value); NOT NEEDED

		generated.setPurp(createPurpose()); // maybe set NO purpose instead
											// of complicated not-fitting codes?

		generated.setRmtInf(createRemittanceInformation(currentDebtor));

		return generated;

	}

	private DirectDebitTransactionSDD createDrctDbtTx(Debtor currentDebtor) {
		DirectDebitTransactionSDD drctdbttx = OBJECT_FACTORY
				.createDirectDebitTransactionSDD();

		MandateRelatedInformationSDD mandateRelatedInformation = OBJECT_FACTORY
				.createMandateRelatedInformationSDD();

		mandateRelatedInformation.setMndtId(currentDebtor.getMandate());

		mandateRelatedInformation.setDtOfSgntr(datatypeFactory
				.newXMLGregorianCalendar(currentDebtor
						.getMandateSignatureDate()));

		mandateRelatedInformation.setAmdmntInd(false);

		// mandateRelatedInformation.setElctrncSgntr(Max1025Text); not needed
		// because paper based mandate

		drctdbttx.setMndtRltdInf(mandateRelatedInformation);

		// drctdbttx.setCdtrSchmeId(value) is set on Payment Information level

		return drctdbttx;
	}

	private PurposeSEPA createPurpose() {
		PurposeSEPA purpose = OBJECT_FACTORY.createPurposeSEPA();
		purpose.setCd("OTHR");
		return purpose;
	}

	private RemittanceInformationSEPA1Choice createRemittanceInformation(
			Debtor currentDebtor) {
		RemittanceInformationSEPA1Choice remititanceInformation = OBJECT_FACTORY
				.createRemittanceInformationSEPA1Choice();
		remititanceInformation.setUstrd(currentDebtor.getUnstructuredPurpose());
		// Structured Remittance is recommended not to set

		return remititanceInformation;
	}

	private PaymentIdentificationSEPA createPaymentIdentification(
			Debtor currentDebitor) {
		PaymentIdentificationSEPA pisepa = OBJECT_FACTORY
				.createPaymentIdentificationSEPA();

		pisepa.setEndToEndId(currentDebitor.getMandate()); // TODO EndToEndId
															// Debitor-Mandate
															// sinnvoll?
		/*
		 * sets the unique reference End-to-End ID, has to meet the
		 * RestrictedIdentificationSEPA1 specifications, otherwise can be chosen
		 * at will
		 */

		/*
		 * pisepa.setInstrId();
		 * 
		 * NOT NEEDED reference ID from a direct debit presenter to his bank
		 * (only used by technical service provider)
		 */

		return pisepa;
	}

	private ActiveOrHistoricCurrencyAndAmountSEPA createInstructionAmount(
			Debtor currentDebtor) {
		ActiveOrHistoricCurrencyAndAmountSEPA ccy = OBJECT_FACTORY
				.createActiveOrHistoricCurrencyAndAmountSEPA();

		ccy.setCcy(ActiveOrHistoricCurrencyCodeEUR.EUR);
		ccy.setValue(currentDebtor.getBookingVolume());
		return ccy;
	}

	@SuppressWarnings("unused")
	private PartyIdentificationSEPA1 createUltimateCreditor() {
		PartyIdentificationSEPA1 pidentsepa1 = OBJECT_FACTORY
				.createPartyIdentificationSEPA1();

		// pidentsepa1.setId(value) not to set here

		pidentsepa1.setNm("Nm");
		return pidentsepa1;
	}

	private BranchAndFinancialInstitutionIdentificationSEPA3 createDebtorAgent(
			Debtor currentDebtor) {
		BranchAndFinancialInstitutionIdentificationSEPA3 debtorAgent = OBJECT_FACTORY
				.createBranchAndFinancialInstitutionIdentificationSEPA3();
		FinancialInstitutionIdentificationSEPA3 financialInstituationIdent = OBJECT_FACTORY
				.createFinancialInstitutionIdentificationSEPA3();
		financialInstituationIdent.setBIC(currentDebtor.getBIC());
		debtorAgent.setFinInstnId(financialInstituationIdent);
		return debtorAgent;
	}

	private PartyIdentificationSEPA2 createDebtor(Debtor currentDebtor) {
		PartyIdentificationSEPA2 debtor = OBJECT_FACTORY
				.createPartyIdentificationSEPA2();

		debtor.setNm(currentDebtor.getAccountHolder());

		// following information is recommended not to set:

		// PostalAddressSEPA debtorPostAdress =
		// OBJECT_FACTORY.createPostalAddressSEPA();
		// debtorPostAdress.setCtry("COUNTRY");
		// debtor.setPstlAdr(debtorPostAdress);
		//
		// debtor.setId(ID);

		return debtor;
	}

	private CashAccountSEPA2 createDebtorAccount(Debtor currentDebtor) {
		CashAccountSEPA2 debtorAccount = OBJECT_FACTORY
				.createCashAccountSEPA2();
		AccountIdentificationSEPA debtorAccountIdentification = OBJECT_FACTORY
				.createAccountIdentificationSEPA();

		debtorAccountIdentification.setIBAN(currentDebtor.getIBAN());
		debtorAccount.setId(debtorAccountIdentification);

		return debtorAccount;
	}

}
